﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.WindowsMobile.PocketOutlook;
using System.Xml;
using System.ComponentModel;


namespace GoogleVoice
{
    public class Connection
    {
        public  enum Status
        {
            NotLoggedIn,
            LoginFailed,
            NoStorageCard,
            LoggedIn,
            CacheOnly // not implemented
        };
        private string authToken;
        public string AuthToken
        {
            get { return authToken; }
            set { authToken = value; }
        }
        private Status connectionStatus;
        public Status ConnectionStatus
        {
            get { return connectionStatus; }
            set { connectionStatus = value; }
        }

        public Connection()
        {
            connectionStatus = Status.NotLoggedIn;
        }
        public void Login(string email, string password)
        {


            if (Directory.Exists("\\Storage Card\\"))
            {
                if (!Directory.Exists("\\Storage Card\\GoogleVoice\\"))
                {
                    Directory.CreateDirectory("\\Storage Card\\GoogleVoice\\");
                }
            }
            else
            {
                connectionStatus = Status.NoStorageCard;
                return;
            }

            string path = "\\Storage Card\\GoogleVoice\\Settings.xml";
            XmlDocument xmldoc = new XmlDocument();
            if (!File.Exists(path))
            {
                TextWriter tw = new StreamWriter(path);
                tw.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
                tw.WriteLine("<GoogleVoice>");
                tw.WriteLine("  <settings>");
                tw.WriteLine("    <authCode></authCode>");
                tw.WriteLine("  </settings>");
                tw.WriteLine("</GoogleVoice>");
                tw.Close();
            }
            xmldoc.Load(path);
            XmlNode node = xmldoc.DocumentElement;
            authToken = node.SelectSingleNode("/GoogleVoice/settings/authCode").InnerText;


            if (authToken != "" && connectionStatus != Status.LoginFailed)
            {
                connectionStatus = Status.NotLoggedIn;
                return;
            }


            if (connectionStatus == Status.LoginFailed || authToken == "")
            {
                HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create("https://www.google.com/accounts/ClientLogin");
                byte[] buffer = Encoding.ASCII.GetBytes("accountType=HOSTED_OR_GOOGLE&Email=" + email + "&Passwd=" + password + "&service=grandcentral&source=w00t-GVVVM-.1");
                webReq.Method = "POST";
                webReq.ContentLength = buffer.Length;
                webReq.ContentType = "application/x-www-form-urlencoded";
                authToken = "";
                try
                {
                    Stream PostData = webReq.GetRequestStream();
                    PostData.Write(buffer, 0, buffer.Length);
                    PostData.Close();

                    //Get the response handle, we have no true response yet!
                    HttpWebResponse response = (HttpWebResponse)webReq.GetResponse();

                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        connectionStatus = Status.LoginFailed;
                        return;
                    }
                    // Get the stream associated with the response.
                    Stream receiveStream = response.GetResponseStream();

                    // Pipes the stream to a higher level stream reader with the required encoding format. 
                    StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
                    string outStream = readStream.ReadToEnd();
                    authToken = outStream;
                    int startstr = authToken.IndexOf("\nAuth=") + 6;
                    authToken = authToken.Substring(startstr).TrimEnd("\n".ToCharArray());
                    node.SelectSingleNode("/GoogleVoice/settings/authCode").InnerText = authToken;
                    xmldoc.Save(path);
                    connectionStatus = Status.LoggedIn;
                    response.Close();
                    readStream.Close();
                    return;

                }
                catch (Exception ex)
                {
                    connectionStatus = Status.LoginFailed;

                }
            }
            
        }

        private VoiceMails myVoiceMails;
        public VoiceMails MyVoiceMails
        {
            get { return myVoiceMails; }
            set { myVoiceMails = value; }
        }


        public string GetData(string url)
        {

            HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create("https://www.google.com/voice/" + url + "?auth=" + authToken);
            webReq.Method = "GET";
            string outStream = "";

            
            /* byte[] buffer = Encoding.ASCII.GetBytes("auth=" + Uri.EscapeUriString(authToken));
             webReq.ContentLength = buffer.Length;
             webReq.ContentType = "application/x-www-form-urlencoded";
            
             */
             try
             {
            
            //Get the response handle, we have no true response yet!
                HttpWebResponse response = (HttpWebResponse)webReq.GetResponse();

                if (response.ResponseUri.ToString().Contains("ServiceLogin"))
                {
                    connectionStatus = Status.NotLoggedIn;
                    return "needlogin";

                }
                
                // Get the stream associated with the response.
                Stream receiveStream = response.GetResponseStream();
                

                // Pipes the stream to a higher level stream reader with the required encoding format. 
                StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
                outStream = readStream.ReadToEnd();
                
                response.Close();
                readStream.Close();
                connectionStatus = Status.LoggedIn;

            }
            catch 
             {
                 connectionStatus = Status.LoginFailed;
            
            }
            return outStream;
        }

        public bool GetInbox()
        {
            IsDownloaded = false;
            string path = "\\Storage Card\\GoogleVoice\\VoiceMails.xml";
            XmlDocument xmldoc = new XmlDocument();
            try
            {
                xmldoc.Load(path);
            }
            catch
            {
                TextWriter tw = new StreamWriter(path);
                tw.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
                tw.WriteLine("<GoogleVoice>");
                tw.WriteLine("  <voicemails>");
                tw.WriteLine("  </voicemails>");
                tw.WriteLine("</GoogleVoice>");
                tw.Close();
                xmldoc.Load(path);
            }
            XmlNode node = xmldoc.DocumentElement;
            XmlNodeList nl = node.SelectNodes("/GoogleVoice/voicemails/VoiceMail");
            VoiceMails vms = new VoiceMails();
            foreach (XmlNode vn in nl)
            {
                VoiceMail thisVoiceMail = new VoiceMail();
                thisVoiceMail.ID = vn.SelectSingleNode("ID").InnerText;
                thisVoiceMail.DisplayNumber = vn.SelectSingleNode("DisplayNumber").InnerText;
                thisVoiceMail.DisplayStartDateTime = DateTime.Parse(vn.SelectSingleNode("DisplayStartDateTime").InnerText);
                thisVoiceMail.Note = vn.SelectSingleNode("Note").InnerText;
                thisVoiceMail.IsRead = bool.Parse(vn.SelectSingleNode("IsRead").InnerText);
                thisVoiceMail.IsSpam = bool.Parse(vn.SelectSingleNode("IsSpam").InnerText);
                thisVoiceMail.IsTrash = bool.Parse(vn.SelectSingleNode("IsTrash").InnerText);
                thisVoiceMail.Star = bool.Parse(vn.SelectSingleNode("Star").InnerText);
                thisVoiceMail.FilePath = vn.SelectSingleNode("FilePath").InnerText;
                thisVoiceMail.IsDownloaded = File.Exists(thisVoiceMail.FilePath);
                thisVoiceMail.Transcription = vn.SelectSingleNode("Transcription").InnerText;
                thisVoiceMail.DisplayName = vn.SelectSingleNode("DisplayName").InnerText;
                vms.Add(thisVoiceMail);
                
            }

            myVoiceMails = vms;
            if (myVoiceMails.Count > 0) connectionStatus = Status.CacheOnly;
            xmldoc = null;
            ThreadStart starter = delegate { DownloadInbox(); };
            Thread dlThread = new Thread(starter);
            dlThread.Priority = ThreadPriority.Lowest;
            dlThread.Start();
            return true;

        }
        public bool IsDownloaded;
        private void DownloadInbox()
        {
            string path = "\\Storage Card\\GoogleVoice\\VoiceMails.xml";
            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(path);
            XmlNode node = xmldoc.DocumentElement;
            node = node.SelectSingleNode("/GoogleVoice/voicemails");
            node.RemoveAll();
            
            string xml = GetData("inbox/recent/voicemail/");
            VoiceMails dlVoiceMails = new VoiceMails();
            if (xml.Length > 100)
            {
                string tmpStr = xml.Substring(0, xml.IndexOf("\"totalSize\""));
                string[] aryVoiceMails = tmpStr.Split("{".ToCharArray());
                foreach (string strVoicemail in aryVoiceMails)
                {
                    if (strVoicemail.Contains("\"id\""))
                    {
                        VoiceMail thisVoicemail = new VoiceMail();
                        int iStart = strVoicemail.IndexOf("id") + 5;
                        thisVoicemail.ID = strVoicemail.Substring(iStart, strVoicemail.IndexOf("\"", iStart) - iStart);
                        iStart = strVoicemail.IndexOf("displayNumber") + 16;
                        thisVoicemail.DisplayNumber = strVoicemail.Substring(iStart, strVoicemail.IndexOf("\"", iStart) - iStart);
                        iStart = strVoicemail.IndexOf("displayStartDateTime") + 23;
                        thisVoicemail.DisplayStartDateTime = DateTime.Parse(strVoicemail.Substring(iStart, strVoicemail.IndexOf("\"", iStart) - iStart));
                        iStart = strVoicemail.IndexOf("note") + 7;
                        thisVoicemail.Note = strVoicemail.Substring(iStart, strVoicemail.IndexOf("\"", iStart) - iStart);
                        iStart = strVoicemail.IndexOf("isRead") + 8; // bools aren't in quotes so they're a bit different
                        thisVoicemail.IsRead = bool.Parse(strVoicemail.Substring(iStart, strVoicemail.IndexOf(",", iStart) - iStart));
                        iStart = strVoicemail.IndexOf("isSpam") + 8;
                        thisVoicemail.IsSpam = bool.Parse(strVoicemail.Substring(iStart, strVoicemail.IndexOf(",", iStart) - iStart));
                        iStart = strVoicemail.IndexOf("isTrash") + 9;
                        thisVoicemail.IsTrash = bool.Parse(strVoicemail.Substring(iStart, strVoicemail.IndexOf(",", iStart) - iStart));
                        iStart = strVoicemail.IndexOf("star\":") + 6;
                        thisVoicemail.Star = bool.Parse(strVoicemail.Substring(iStart, strVoicemail.IndexOf(",", iStart) - iStart));
                        if (File.Exists("\\Storage Card\\GoogleVoice\\" + thisVoicemail.ID + ".mp3"))
                        {
                            thisVoicemail.IsDownloaded = true;
                            thisVoicemail.FilePath = "\\Storage Card\\GoogleVoice\\" + thisVoicemail.ID + ".mp3";
                        }
                        else thisVoicemail.IsDownloaded = false;
                        iStart = xml.IndexOf("gc-message-message-display", xml.IndexOf("<div id=\"" + thisVoicemail.ID)) + 28;
                        thisVoicemail.Transcription = Utils.StripHTML(xml.Substring(iStart, xml.IndexOf("</div>", iStart) - iStart));
                        if (thisVoicemail.DisplayNumber != "")
                        {
                            OutlookSession poomSession = new OutlookSession();
                            ContactCollection contacts = poomSession.Contacts.Items;
                            PropertyDescriptor pdContactMobile = TypeDescriptor.GetProperties(typeof(Contact))["MobileTelephoneNumber"];
                            PropertyDescriptor pdContactHome = TypeDescriptor.GetProperties(typeof(Contact))["HomeTelephoneNumber"];
                            PropertyDescriptor pdContactBusiness = TypeDescriptor.GetProperties(typeof(Contact))["BusinessTelephoneNumber"];
                            string displayName = thisVoicemail.DisplayNumber;
                            int foundIndex = -1;
                            foundIndex = contacts.Find(pdContactMobile, thisVoicemail.DisplayNumber);
                            if (foundIndex == -1) foundIndex = contacts.Find(pdContactHome, thisVoicemail.DisplayNumber);
                            if (foundIndex == -1) foundIndex = contacts.Find(pdContactBusiness, thisVoicemail.DisplayNumber);
                            if (foundIndex != -1) displayName = contacts[foundIndex].FirstName + " " + contacts[foundIndex].LastName;
                            thisVoicemail.DisplayName = displayName;
                        }
                        else thisVoicemail.DisplayName = "Unknown";
                            


                        XmlElement vn = xmldoc.CreateElement("VoiceMail");
                        XmlElement vp;
                        vp = xmldoc.CreateElement("ID");
                        vp.InnerText = thisVoicemail.ID;
                        vn.AppendChild(vp);
                        vp = xmldoc.CreateElement("DisplayNumber");
                        vp.InnerText = thisVoicemail.DisplayNumber;
                        vn.AppendChild(vp);
                        vp = xmldoc.CreateElement("DisplayName");
                        vp.InnerText = thisVoicemail.DisplayName;
                        vn.AppendChild(vp);
                        vp = xmldoc.CreateElement("DisplayStartDateTime");
                        vp.InnerText = thisVoicemail.DisplayStartDateTime.ToString();
                        vn.AppendChild(vp);
                        vp = xmldoc.CreateElement("Note");
                        vp.InnerText = thisVoicemail.Note;
                        vn.AppendChild(vp);
                        vp = xmldoc.CreateElement("IsRead");
                        vp.InnerText = thisVoicemail.IsRead.ToString();
                        vn.AppendChild(vp);
                        vp = xmldoc.CreateElement("IsSpam");
                        vp.InnerText = thisVoicemail.IsSpam.ToString();
                        vn.AppendChild(vp);
                        vp = xmldoc.CreateElement("IsTrash");
                        vp.InnerText = thisVoicemail.IsTrash.ToString();
                        vn.AppendChild(vp);
                        vp = xmldoc.CreateElement("Star");
                        vp.InnerText = thisVoicemail.Star.ToString();
                        vn.AppendChild(vp);
                        vp = xmldoc.CreateElement("IsDownloaded");
                        vp.InnerText = thisVoicemail.IsDownloaded.ToString();
                        vn.AppendChild(vp);
                        vp = xmldoc.CreateElement("FilePath");
                        vp.InnerText = thisVoicemail.FilePath;
                        vn.AppendChild(vp);
                        vp = xmldoc.CreateElement("Transcription");
                        vp.InnerText = thisVoicemail.Transcription;
                        vn.AppendChild(vp);


                        node.AppendChild(vn);
                        try
                        {
                            xmldoc.Save(path);
                        }
                        catch { }

                        dlVoiceMails.Add(thisVoicemail);
                    }
                }
                myVoiceMails = dlVoiceMails;

            }
            OnDownloadComplete(EventArgs.Empty);
        }
        public event System.EventHandler DownloadComplete;
        protected virtual void OnDownloadComplete(System.EventArgs e)
        {
            if (DownloadComplete != null)
            {
                DownloadComplete(this, e);
            }
        }


    }

    public class VoiceMail
    {
        #region variables
        private string id;
        private string filePath;
        public string FilePath
        {
            get { return filePath; }
            set { filePath = value; }
        }
        public string ID
        {
            get { return id; }
            set { id = value; }
        }

        private string displayNumber;
        public string DisplayNumber
        {
            get { return displayNumber; }
            set { displayNumber = value; }
        }

        private DateTime displayStartDateTime;
        public DateTime DisplayStartDateTime
        {
            get { return displayStartDateTime; }
            set { displayStartDateTime = value; }
        }

        private string note;
        public string Note
        {
            get { return note; }
            set { note = value; }
        }

        private bool isRead;
        public bool IsRead
        {
            get { return isRead; }
            set { isRead = value; }
        }

        private bool isSpam;
        public bool IsSpam
        {
            get { return isSpam; }
            set { isSpam = value; }
        }

        private bool isTrash;
        public bool IsTrash
        {
            get { return isTrash; }
            set { isTrash = value; }
        }

        private bool star;
        public bool Star
        {
            get { return star; }
            set { star = value; }
        }

        private string trasnscription;
        public string Transcription
        {
            get { return trasnscription; }
            set { trasnscription = value; }
        }
        private string displayName;
        public string DisplayName
        {
            get { return displayName; }
            set { displayName = value; }
        }
        #endregion variables

        public VoiceMail()
        {
            id = "";
            displayNumber = "";
            displayStartDateTime = DateTime.MinValue;
            note = "";
            trasnscription = "";
            filePath = "";
            IsDownloaded = false;

        }
        public bool IsDownloaded;
        private void download(string authToken)
        {
            byte[] downloadedData = new byte[0];
            string url = "https://www.google.com/voice/media/send_voicemail/" + id + "?auth=" + authToken;
            try
            {
                //Get a data stream from the url
                WebRequest req = WebRequest.Create(url);
                WebResponse response = req.GetResponse();
                Stream stream = response.GetResponseStream();

                //Download in chuncks
                byte[] buffer = new byte[1024];

                //Get Total Size
                int dataLength = (int)response.ContentLength;

                //Download to memory
                //Note: adjust the streams here to download directly to the hard drive
                FileStream fileStream = new FileStream(filePath, FileMode.Create);
                while (true)
                {
                    //Try to read the data
                    int bytesRead = stream.Read(buffer, 0, buffer.Length);

                    if (bytesRead == 0)
                    {
                        break;
                    }
                    else
                    {
                        //Write the downloaded data
                        fileStream.Write(buffer, 0, bytesRead);
                    }
                }

                //Convert the downloaded stream to a byte array


                //Clean up
                stream.Close();
                fileStream.Close();
                IsDownloaded = true;
                
            }
            catch (Exception)
            {
                filePath = "";
            }

            OnDownloadComplete(EventArgs.Empty);
        }
       
        public void Download(string authToken)
        {
            
            filePath = "\\Storage Card\\GoogleVoice\\" + id + ".mp3";
            ThreadStart starter = delegate { download(authToken); };
            Thread dlThread = new Thread(starter);
            dlThread.Priority = ThreadPriority.Lowest;
            dlThread.Start();
            

        }
        public event System.EventHandler DownloadComplete;
        protected virtual void OnDownloadComplete(System.EventArgs e)
        {
            if (DownloadComplete != null)
            {
                DownloadComplete(this, e);
            }
        }
        
        private SoundPlayer snd;
        public void Play()
        {
            snd = new SoundPlayer();
            snd.SoundLocation = filePath;
            snd.Play();
        }
        public void Stop()
        {
            if(snd != null) snd.Stop();
        }

    }

    public class VoiceMails : List<VoiceMail>
    {
    }
    public class Utils
    {
        public static string StripHTML(string source)
        {
            return Regex.Replace(Regex.Replace(source, "<.*?>", string.Empty), @"\s+", " ");
        }
    }
}
